ARIA Accordions
Expected behaviors
All accordion triggering elements should be in the tab order, pressing Enter or Space should expand the desired accordion panel, the expanded state should be toggled appropriately on the triggering element, and the expanded accordion panel should be rendered directly after the triggering element in the tab order.
Though similar in both concept and execution to Tab controls, accordions are not the same. A Tab control has a series of grouped triggering elements that expand and collapse, the rendered content of which is inserted directly after the triggering element group when opened. The container element insertion point for all Tab control triggering elements is shared between them. Also, the group of triggering elements in a Tab control has only one tab stop. The arrow keys are then used to switch focus between each Tab, and the Enter or Space key is used to expand the desired Tab content panel.
In contrast, an Accordion has a series of triggering elements that expand and collapse, the rendered content of which is inserted directly after the triggering element when opened. The container element insertion points for Accordions are not shared. Also, all Accordion links appear in the tab order. The reason why ARIA attributes such as role="tablist" and role="tab" are not included within accordions, is because the insertion of inline content would place dynamic content sections within the same Tablist container, making it impossible to determine the order of nested Tab controls when present within the inserted content. The chosen implementation should always match the UI that it's being applied to, to prevent confusion.
The 4X ARIA Accordion module automatically configures all required ARIA attributes and focus handling, in strict accordance with the ARIA specification.
Note: An accordion is a composite widget, meaning that it is comprised of different ARIA roles and supporting attributes.
The following attributes are handled automatically by the Accordion module:
- role=button
- aria-expanded
- aria-controls
- role=region
- aria-labelledby
- tabindex
Available attributes for the triggering element:
- data-controls : The resource path and pointer to the ID attribute of the accordion container element.
- data-root : The ID attribute of the container element where the accordion content will be inserted when rendered. (This must not be inside the triggering element)
- data-active : Specifies that the referenced accordion node will open automatically. Only one accordion node per group should include this attribute.
- aria-disabled : When set to "true" on the triggering element, will automatically disable associated functionality.
Note: When dynamically disabling a triggering element, the 4X setDisabled() function should be used to set the disabled state of the triggering element. This will ensure proper background mapping.
$A.setDisabled(triggeringElement, boolean);
HTML syntax
<h2>
<button data-active data-root="root-id-for-billing" data-controls="accordion-panel-id-for-billing" > BILLING </button>
</h2>
<div id="root-id-for-billing">
<div id="accordion-panel-id-for-billing">
Expandable content for the billing section here. (Content visible by default via the data-active attribute on the triggering element.)
</div>
</div>
<h2>
<button data-root="root-id-for-shipping" data-controls="accordion-panel-id-for-shipping" > SHIPPING </button>
</h2>
<div id="root-id-for-shipping">
<div hidden id="accordion-panel-id-for-shipping">
Expandable content for the shipping section here. (Content hidden by default via the hidden attribute on the accordion panel.)
</div>
</div>
IMPORTANT: The triggering element must not include any other active elements, otherwise these will not be accessible to non-sighted screen reader users.
When aria-disabled="true" is set on an accordion triggering element, functionality for that accordion panel will automatically be disabled.
JavaScript syntax
$A.setAccordion( domNodeListOrCSSSelectorForTriggeringElements , {
// Configure functionality key / value mappings
});
- Module file: Accordion.js
- Requires: AccName.js, RovingTabIndex.js.
- Recommended: Velocity.js, VelocityUI.js.
Parameters
- A DOM element or CSS selector to specify the triggering elements
- A configuration map to customize behaviors and options
Configuration
{
// Optionally set a single tab stop for associated accordion triggering elements.
singleTabStop: false,
// Auto configure orientation using dynamic switching based on the visual layout of focusable elements.
// Only applicable when singleTabStop is true.
// "off"=Inactive, "semi"=Switches between vertical and horizontal only, "full"= Switches between vertical, horizontal, and both when line-wrapping is detected.
autoSwitch: "full",
// Optionally extend the RTI instance with custom event handlers.
// Only applicable when singleTabStop is true.
// For available options, view the RovingTabIndex help doc at "Help/Module Imports/Actions/RovingTabIndex".
extendRTI: {
// Optional event handlers.
},
// Optionally choose to track the browser history when each panel is opened.
// May be used to automatically open the same panel after the page is bookmarked.
// Requires that each accordion triggering element include a unique id attribute.
trackPage: false,
// Toggle the specified class name on the triggering element when hidden or shown.
toggleClassName: "open",
// Optionally toggle the hidden attribute instead of inserting the accordion panel when rendered.
toggleHide: false,
// Specify that the collection of accordion triggering elements will function like toggles, where the currently open panel can be closed.
isToggle: false,
// Specify that the collection of accordion triggering elements will function as independant objects, where multiple panels may be open at the same time.
allowMultiple: false,
// Preload markup in the background when using the Fetch API to load external content.
preload: true,
// Preload images in the background when using the Fetch API to load external content.
preloadImages: true,
// Optionally run a script after the accordion panel finishes rendering.
afterRender: function(DC) {
// DC.container includes the rendered accordion content.
},
// Optionally run a script after the accordion panel is removed.
afterRemove: function(DC) {
// Do something.
},
/*
// Enable auto-rendering when the page loads.
// When true, the hash tag in the URL will automatically open the associated DC object.
// To render automatically, the hash tag must match the DC object id.
// To set a hash tag within the address bar, use the $A.setPage() function.
// For more details, view: Help/ARIA Development/Browser History and Permalinks
// Plus: Help/DC API/DC Object Configuration/Behaviors
trackPage: true,
afterRender: function(dc) {
$A.setPage(
dc.id,
$A.getText(dc.triggerNode) + " ARIA Accordion - Apex 4X Technical Style Guide"
);
},
*/
// Optionally specify a render and remove animation effect for the accordion.
// Requires the "Animate" module import to function, which is powered by Velocity.js.
// To ignore animation effects, delete the animate object declaration entirely from the setup script.
// View implementations within "Templates/Accordions" for practical animation usage examples.
style: { display: "none" }, // Set the initial state to hidden in prep for animation.
animate: {
onRender: function(dc, wrapper, next) {
// Specify the render animation effect, including the callback function statement to execute when the animation effect completes.
Velocity(wrapper, "transition.TYPE", {
// Velocity options here, plus the callback declaration after the animation completes.
complete: function() {
next(); // REQUIRED: next() must be executed so control is passed back to 4X for rendering.
}
});
},
onRemove: function(dc, wrapper, next) {
// Specify the removal animation effect, including the callback function statement to execute when the animation effect completes.
Velocity(wrapper, "transition.TYPE", {
// Velocity options here, plus the callback declaration after the animation completes.
complete: function() {
next(); // REQUIRED: next() must be executed so control is passed back to 4X for removal.
}
});
}
}
// (Additional DC API properties and methods can be declared here also to customize functionality and behavior)
// To view available options, reference the help docs located at: "Help/DC API/DC Object Configuration"
}
Programmatic control
// Get the DC object for the accordion using its triggering element id.
var DC = $A("accordionTriggerId");
// Open the accordion manually.
DC.render(function() {
// Optionally do something after rendering completes.
});
// Close the accordion manually.
DC.remove(function() {
// Optionally do something after removal completes.
});
// Additional DC API properties and methods can be applied here as well.
// To view available options, reference the help docs located at: "Help/DC API/DC Object Properties and Methods"